/*
    Copyright (c) 2007-2008 by Mikhail Borbot <mike_n@hotbox.ru>

    This file is part of mlog

    mlog is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    mlog is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with mlog.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "log.h"
#include <boost/thread.hpp>
#include <stdlib.h>
#include <time.h>

extern mlog::cmodule_logger_itf& log1;
extern mlog::cmodule_logger_itf& _log2;
extern mlog::cmodule_logger_itf& log3;

// perform a log action, which is randomly decided
void log_action()
{
	static const int test_30 = RAND_MAX/3;
	static const int test_5 = RAND_MAX/20;
	static const int test_2 = RAND_MAX/50;
	// each log has a chance to be used
	bool do1 = ::rand() < test_30;
	bool do2 = ::rand() < test_30;
	bool do3 = ::rand() < test_30;
	// there is a chance to change tag
	if (do1 && ::rand() < test_2)
	{
//#ifndef _DEBUG
		std::stringstream strm;
		strm << "1state" << ::rand();
		log1.set_tag("global-state", strm.str().c_str());
//#endif
	}
	if (do3 && ::rand() < test_2)
	{
//#ifndef _DEBUG
		std::stringstream strm;
		strm << "3state" << ::rand();
		log3.set_tag("global-state", strm.str().c_str());
//#endif
	}
	// select log level
	int level = 1 + ::rand() % mlog::trace;
	// log something
	if (do1)
		LOGC(log1, level) << "1CONSISTENCY_CHECK_" << 1 << "_LOGGED_" << 8;
	if (do2)
		LOGC(_log2, level) << "2CONSISTENCY_CHECK_" << 2 << "_LOGGED_" << 9;
	if (do3)
		LOGC(log3, level) << "3CONSISTENCY_CHECK_" << 3 << "_LOGGED_" << 10;
	// sometimes log Hello, world!
	if (::rand() < test_5)
	{
		if (do1)
			LOGC(log1, mlog::crit) << "Hello, world!";
		if (do2)
			LOGC(_log2, mlog::crit) << "Hello, world!";
		if (do3)
			LOGC(log3, mlog::crit) << "Hello, world!";
	}
}

extern int g_allocations;

static boost::mutex g_srand_once;
static unsigned int now_srand = static_cast<unsigned int>(::time(NULL));

void thread_func()
{
	// initialize
	{
		boost::mutex::scoped_lock lock(g_srand_once);
		::srand(now_srand);
		now_srand = ::rand();
	}
	// each thread logs up to 10000 messages
	int count = ::rand() % 10000;
	LOGC(log1, mlog::warn) << boost::this_thread::get_id() << " HAS " << count << " OPERATIONS";
	LOGC(_log2, mlog::warn) << boost::this_thread::get_id() << " HAS " << count << " OPERATIONS";
	LOGC(log3, mlog::warn) << boost::this_thread::get_id() << " HAS " << count << " OPERATIONS";
	for (int i = 0; i < count; i++)
	{
		log_action();
		// sleep up to 20 ms
		boost::this_thread::sleep(boost::posix_time::milliseconds(::rand()%20));
#if defined(_DEBUG) && defined(_WIN32)
		if (::rand() < RAND_MAX/10)
			LOGC(log1, mlog::warn) << "Allocations: " << g_allocations;
#endif
	}
}

void run_tests()
{
	log1.set_tag("global-state", "starting");
	log3.set_tag("global-state", "starting");
	LOGC(log1, mlog::crit) << "Starting tests...";
	LOGC(_log2, mlog::crit) << "Starting tests...";
	LOGC(log3, mlog::crit) << "Starting tests...";
	// start some threads...
	boost::thread_group grp;
	for (int i = 0; i < 256; i++)
		grp.create_thread(thread_func);
	// wait
	grp.join_all();
}
